package xyz.gzdxc.common.service.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import xyz.gzdxc.common.constant.LoginConstant;
import xyz.gzdxc.common.mysql.entity.CaptchaEntity;
import xyz.gzdxc.common.mysql.entity.SessionEntity;
import xyz.gzdxc.common.mysql.entity.UserEntity;
import xyz.gzdxc.common.exception.AccountLockException;
import xyz.gzdxc.common.exception.CaptchaException;
import xyz.gzdxc.common.exception.CaptchaTimeoutException;
import xyz.gzdxc.common.exception.UserLoginException;
import xyz.gzdxc.common.mysql.repository.CaptchaRepository;
import xyz.gzdxc.common.mysql.repository.SessionRepository;
import xyz.gzdxc.common.mysql.repository.UserRepository;
import xyz.gzdxc.common.service.LoginService;
import xyz.gzdxc.common.util.CheckCodeUtil;
import xyz.gzdxc.common.util.DateUtil;
import xyz.gzdxc.common.vo.request.LoginReqVo;
import xyz.gzdxc.common.vo.response.CaptchaResp;

import java.rmi.ServerException;
import java.util.Date;
import java.util.UUID;

@Service
public class LoginServiceImpl implements LoginService {
    private static final Logger LOG = LoggerFactory.getLogger(LoginServiceImpl.class);

    @Autowired
    CaptchaRepository captchaRepository;

    @Autowired
    SessionRepository sessionRepository;

    @Autowired
    UserRepository userRepository;

    @Override
    public CaptchaResp getCheckCode() throws Exception {
        int captchaLen = 4;
        String captchaSet = "1aA";
        CheckCodeUtil checkCodeUtil = new CheckCodeUtil();
        CaptchaEntity captchaEntity = checkCodeUtil.getCheckCodeImage(captchaLen, captchaSet);
        String uuId = UUID.randomUUID().toString();
        uuId = uuId.replace("-", "").toLowerCase();
        captchaEntity.setSession(uuId);
        captchaEntity.setCreateTime(new Date());
        LOG.info("the generated check code => {}", captchaEntity);
        CaptchaEntity save = captchaRepository.save(captchaEntity);
        if(save == null){
            LOG.info("save the captchaEntity to db fail");
            throw new Exception();
        }
        LOG.info("the return baseCode => {}", save.getBaseCode());
        LOG.info("the return captcha session => {}", save.getSession());
        CaptchaResp captchaResp = new CaptchaResp();
        captchaResp.setBaseCode(save.getBaseCode());
        captchaResp.setSession(save.getSession());
        return captchaResp;
    }

    @Override
    public String login(LoginReqVo loginReqVo) throws Exception {
        CaptchaEntity captchaEntity = null;
        try{
            captchaEntity = captchaRepository.findBySession(loginReqVo.getCaptchaSession());
        }catch (Exception e){
            e.printStackTrace();
            throw new ServerException("Server Exception!");
        }

        if(captchaEntity == null){
            throw new CaptchaException("check code error!");
        }
        Long captchaDiffTime = DateUtil.getTimeDiffInMin(captchaEntity.getCreateTime());
        if(captchaDiffTime > LoginConstant.CAPTCHA_TIMEOUT_MIN){
            throw new CaptchaTimeoutException("the check code has expired");
        }
        //check the check code whether correct or not, ignore the character case
        if(!captchaEntity.getCode().equalsIgnoreCase(loginReqVo.getCaptcha())){
            throw new CaptchaException("check code error!");
        }

        UserEntity userEntity = null;
        try{
            userEntity = userRepository.findByAccount(loginReqVo.getUser());
        }catch (Exception e){
            e.printStackTrace();
            throw new ServerException("Server Exception!");
        }
        //check whether the user exists or not
        if(userEntity == null){
            throw new UserLoginException("user not exists or password error!");
        }

        //the user whether locked or not
        if(LoginConstant.USER_LOCK_FLAG.equals(userEntity.getUserLock())){
            throw new AccountLockException("the user has been locked!");
        }

        if(!userEntity.getPassword().equals(loginReqVo.getPwd())){
            userEntity.setErrorNum(userEntity.getErrorNum() + 1);
            if(userEntity.getErrorNum() >= LoginConstant.ERROR_NUM){
                userEntity.setUserLock(LoginConstant.USER_LOCK_FLAG);
            }
            try{
                userRepository.updateErrorNumAndUserLockById(userEntity.getId(), userEntity.getErrorNum(), userEntity.getUserLock());
            }catch (Exception e){
                e.printStackTrace();
                throw new ServerException("Server Exception!");
            }
            throw new UserLoginException("user not exists or password error!");
        }

        String userSessionId = UUID.randomUUID().toString().replace("-", "").toLowerCase();
        SessionEntity sessionEntity = new SessionEntity();
        sessionEntity.setUserId(userEntity.getId());
        sessionEntity.setLoginSession(userSessionId);
        sessionEntity.setTimeOut(LoginConstant.LOGIN_TIMEOUT_MIN);
        //todo set the ip to the session when login
        sessionEntity.setIp("");
        sessionEntity.setLoginTime(new Date());
        sessionEntity.setSessionTimeOut(DateUtil.calculateSessionTimeoutDate(new Date(), LoginConstant.SESSION_TIMEOUT_HOUR));
        sessionEntity.setUpdateTime(new Date());
        try{
            sessionRepository.save(sessionEntity);
            captchaRepository.deleteById(captchaEntity.getId());
            userRepository.updateErrorNumAndUserLockById(userEntity.getId(), 0, LoginConstant.USER_UNLOCK_FLAG);
        }catch (Exception e){
            e.printStackTrace();
            throw new ServerException("Server Exception!");
        }
        return userSessionId;
    }

    @Override
    public boolean logout(String loginSession) throws Exception{
        SessionEntity sessionEntity = sessionRepository.findByLoginSession(loginSession);
        if(sessionEntity != null){
            sessionRepository.deleteById(sessionEntity.getId());
        }
        return true;
    }
}
